using System;
using System.Collections.Generic;
using System.Text;
using System.Data.SqlClient;
using System.ComponentModel;
using RikMigrations.Providers;
using System.Data.Common;

namespace RikMigrations
{
	public class Column
	{
		bool isCreating;
		List<Command> commands = new List<Command>();

		public Column(Table table, string name)
		{
			this.table = table;
			this.name = name;
		}

		public Column(Table table, string name, Type type)
		{
			this.table = table;
			this.name = name;
			this.type = type;
			isCreating = true;
		}

		public Column(Table table, string name, Type type, int length)
		{
			this.table = table;
			this.name = name;
			this.type = type;
			this.length = length;
			isCreating = true;
		}

		#region Properties
		private Table table;
		public Table Table
		{
			get { return table; }
		}

		private string name;
		public string Name
		{
			get { return name; }
		}

		private Type type;
		public Type Type
		{
			get { return type; }
		}

		private string sqlType;
		/// <summary>
		/// Provides an explicit sql type. This should be used sparingly, use Type if possible
		/// </summary>
		public string SqlType
		{
			get { return sqlType; }
			set { sqlType = value; }
		}

		private int length;
		public int Length
		{
			get { return length; }
		}

		private bool isAutoGenerated;
		public bool IsAutoGenerated
		{
			get { return isAutoGenerated; }
			set { isAutoGenerated = value; }
		}
		public Column AutoGenerate() { IsAutoGenerated = true; return this; }

		private bool isPrimaryKey;
		public bool IsPrimaryKey
		{
			get { return isPrimaryKey; }
			set { isPrimaryKey = value; }
		}
		public Column PrimaryKey() { IsPrimaryKey = true; return this; }

		private bool isUnique;
		public bool IsUnique
		{
			get { return isUnique; }
			set { isUnique = value; }
		}
		public Column Unique() { IsUnique = true; return this; }

		private bool allowNull = true;
		[DefaultValue(true)]
		public bool AllowNull
		{
			get { return allowNull; }
			set { allowNull = value; }
		}
		public Column NotNull() { AllowNull = false; return this; }

		private object defaultValue;
		public object DefaultValue
		{
			get { return defaultValue; }
			set { defaultValue = value; }
		}
		public Column Default(object o) { DefaultValue = o; return this; }

		private bool isBlob;
		public bool IsBlob
		{
			get { return isBlob; }
			set { isBlob = value; }
		}
		public Column Blob() { IsBlob = true; return this; }

		private ColumnReference foreignKey;
		public ColumnReference ForeignKey
		{
			get { return foreignKey; }
			set { foreignKey = value; }
		}
		public Column References(string table, string column) { foreignKey = new ColumnReference(table, column); return this; }

		private string extraOptions;
		public string ExtraOptions
		{
			get { return extraOptions; }
		}
		public Column Options(string options) { this.extraOptions = options; return this; }

		private bool isUnicode = true;
		[DefaultValue(true)]
		public bool IsUnicode
		{
			get { return isUnicode; }
		}
		public Column NotUnicode() { this.isUnicode = false; return this; }
		#endregion

		public void Rename(string newName)
		{
			if (isCreating)
				name = newName;
			else
				commands.Add(table.provider.GetRenameTableCommand(this, newName));
		}

		public void Save()
		{
			if (isCreating)
				throw new InvalidOperationException("New columns must be added via Table.Save method");

			foreach (Command command in commands)
				command.Execute(table.provider);
			commands.Clear();
		}

        public Column ChangeType<T>(int length)
        {
            commands.Add(table.provider.GetChangeDataTypeCommand(this.Table.Name, name, typeof(T), length));
            return this;
        }
    }

	public class ColumnReference
	{
		public ColumnReference(string table, string column)
		{
			this.table = table;
			this.column = column;
		}

		#region Properties
		private string table;
		public string Table
		{
			get { return table; }
			set { table = value; }
		}

		private string column;
		public string Column
		{
			get { return column; }
			set { column = value; }
		}
		#endregion
	}
}